<?php
/**
 * Zend_Service_Netflix Class
 * 
 *
 * @author Armando Padilla, armando_padilla_81@yahoo.com
 * @package Zend_Service_Netflix
 * 
 */ 
require_once "Exception.php";

class Zend_Service_Netflix {  
  
    /**
     * Netflix API URI
     */  
    const URI_BASE = "http://api.netflix.com";  
      
    /**
     * NETFLIX API-USER URI
     */  
    const API_USER_URI_BASE = "https://api-user.netflix.com";  
      
    /**
     * OAuth Signiture Method.
     * HMAC-SHA1 OR PLAINTEXT
     */  
    const SIGNITURE_METHOD = 'PLAINTEXT';  
      
    /**
     * OAuth Version
     */  
    const VERSION = '1.0';  
      
    /**
     * Shared Secret.
     *
     * @var unknown_type
     */  
    protected $_sharedSecret = '';  
      
    /**
     * Consumer Key. (Application Id)
     *
     * @var unknown_type
     */  
    protected $_consumerKey = '';  
  
    /**
     * Rest Object. Used for REST calls.
     *
     * @var unknown_type
     */  
    protected $_restClient = null;  
      
    /**
     * Generated Application Name returned by Netflix
     *
     * @var unknown_type
     */  
    protected $_applicationName = '';  
      
      
    /**
     * Generated Request Token Secret by Netflix.
     *
     * @var unknown_type
     */  
    public $requestTokenSecret = '';  
      
    /**
     * Generated Request Token from Netflix.
     *
     * @var unknown_type
     */  
    public $requestToken = '';  
      
      
    /**
     * Access Token Required to Access User data.
     *
     * @var unknown_type
     */  
    public $accessToken = '';  
      
    /**
     * Access Token Secret Required To Access User data.
     *
     * @var unknown_type
     */  
    public $accessTokenSecret = '';  
      
    /**
     * User Id Generated By Netflix.
     *
     * @var unknown_type
     */  
    public $userId = '';  
  
      
    /**
     * Constructor.
     *
     * @param String $applicationId
     * @param String $sharedSecret
     */  
    public function __construct($applicationId, $sharedSecret){
    
    	if(!empty($applicationId)){
			$this->_consumerKey   = $applicationId;
		}else{
			
			throw new Zend_Service_Exception("Application ID Required.");
		}
		
		if(!empty($sharedSecret)){
			
			$this->_sharedSecret  = $sharedSecret;
			
		}else{
			
			throw new Zend_Service_Exception("Shared Secret Required.");
		}	
    
    }  
      
  
    /*****************************
     * CATALOG API 
     *****************************/  
      
    /**
     * Returns a collection of Zend_Service_Netflix_Title objects.
     * 
     * Options:
     * start_index, max_results
     * 
     * API CALL: /catalog/titles
     * 
     * @param String $term
     * @param array $options
     * @return array Zend_Service_Netflix_Title
     */  
    public function getTitles($term, array $options=array()){
    
    	//Validate term
		if(empty($term)){
			throw new Zend_Service_Exception("Auto Complete Term Can Not Be Empty.");	
		}
		
		//Method
		$method = "/catalog/titles";
		
		//Options
		$options['term']   = $term;
		$options['expand'] = "synopsis,
							  cast,
							  directors,
							  formats,
							  screen formats,
							  languages and audio,
							  similars,
							  awards,
							  bonus materials";
		$options           = $this->_buildOptions($options);
		
		//Call REST API
		$restClient = $this->_getRestClient();
		$response   = $restClient->restGet($method, $options);
		
		
		//Check if there are errors
		if(!$response->isError()){
			
			//Initialize Title Container
			$titles = array();
			
			//Get the response
			$content = $response->getBody();
		
			//Parse XML and save titles into contains.
			$simpleXml = simplexml_load_string($content);
			
			//Instantiate Title Objects.
			require_once "Netflix/Title.php";
			foreach($simpleXml->catalog_title as $title){
			
				$Title = new Zend_Service_Netflix_Title();
				$Title->loadXML($title);
				
				array_push($titles, $Title);
				
			}
			
			return $titles;	
			
			
		}else{
			
			throw new Zend_Service_Exception($response->getMessage());
			
		}
    
    }  
      
      
    /**
     * Returns a specific Title as an object. 
     * 
     * type={movie|series|seasons|program|discs}
     * 
     * Options:
     * start_index, max_results
     * 
     * API CALL: 
     * catalog/titles/movies/titleid 
     * catalog/titles/series/seriesId
     * catalog/titles/programs/programId
     * catalog/titles/discs/discId
     * 
     * @param String $titleId Title id.
     * @param String $type
     * @param array $options
     * @return Object Zend_Service_Netflix_Title
     */  
    public function getTitle($titleId, $type='movie', array $options=array()){
    		
    	$types = array("movie", "series", "program", "disc");
    	
		//Validate id.
		if(empty($titleId)){
			throw new Zend_Service_Exception("Title Id Can Not Be Empty.");	
		}
		
		//Validate type.
		if(!in_array($type, $types)){
			throw new Zend_Service_Exception("Type is not valid.");
		}
		
		//Method.
		if($type == "movie"){
			$method = "catalog/titles/movies/".$titleId;
		}
		elseif($type == "series"){
			$method = "catalog/titles/series/".$titleId;
		}	
		elseif($type == "program"){
			$method = "catalog/titles/programs/".$titleId;
		}		
		elseif($type == "disc"){
			$method = "catalog/titles/discs/".$titleId;
		}
		
		//Options
		$options['expand'] = "synopsis,
							  cast,
							  directors,
							  formats,
							  screen formats,
							  languages and audio,
							  similars,
							  awards,
							  bonus materials";
		
		$options = $this->_buildOptions($options);
		
		//Call REST API
		$restClient = $this->_getRestClient();
		$response   = $restClient->restGet($method, $options);
	
		//Check if there are errors
		if(!$response->isError()){
			
			//Get the response
			$content = $response->getBody();
			
			//Create Catalog Object
			$simpleXml = simplexml_load_string($content);
			
			//Instantiate Title Objects.
			require_once "Netflix/Title.php";
			
			$Title = new Zend_Service_Netflix_Title();
			$Title->loadXML($simpleXml);

			return $Title;	
			
		}else{
			
			throw new Zend_Service_Exception($response->getMessage());
			
		}

    }  
  
  
    /**
     * Return a collection of possible String matches or submitted
     * search term. 
     * 
     * API CALL:
     * /catalog/titles/autocomplete
     * 
     * @param String $term Partial or Full title name.
     * @return Array Collection of Full Titles Found.
     */  
    public function getTitlesAutoComplete($term){
    	
    	//Validate term
		if(empty($term)){
			throw new Zend_Service_Exception("Auto Complete Term Can Not Be Empty.");	
		}
		
		//Initialize titles to return
		$titles = array();
		
		//Method
		$method = "catalog/titles/autocomplete";
		
		//Options
		$options['term'] = $term;
		$options         = $this->_buildOptions($options);

		$restClient = $this->_getRestClient();
		$response   = $restClient->restGet($method, $options);

		//Check for errors
		if(!$response->isError()){
			
			//Get the content 
			$content = $response->getBody();
		
			//Create SimpleXML Object 
			$simpleXMLObj = simplexml_load_string($content);

			//Parse the results
			foreach($simpleXMLObj->autocomplete_item as $autocompleteItem){
				
				foreach($autocompleteItem as $title){
					array_push($titles, (string)$title['short']);
				}
			}
			
			return $titles;
			
		}else{
			
			throw new Zend_Service_Exception($response->getMessage());
			
		}	
    	
    }  
  
      
    /**
     * Returns a collection of Zend_Service_Netflix_Title objects simlilar to 
     * the title used as reference.
     * 
     * Options:
     * start_index, max_results
     * 
     * API CALL:
     * /catalog/titles/titleID/similars
     * 
     * @param String $titleId title id.
     * @param Array $options
     */  
    public function getSimilarTitles($titleId, array $options=array()){
    	
    	//Validate id
		if(empty($titleId)){
			throw new Zend_Service_Exception("Missing Title Id.");
		}
		
		//Method
		$method = "catalog/titles/title/".$titleId."/similars";
		
		//Options
		$options['expand'] = "synopsis,
							  cast,
							  directors,
							  formats,
							  screen formats,
							  languages and audio,
							  awards,
							  bonus materials";
		
		$options = $this->_buildOptions($options);
		
		//Call REST API.
		$restClient = $this->_getRestClient();
		$response   = $restClient->restGet($method, $options);
		
	
	
		//If there are errors throw exception otherwise process.
		if(!$response->isError()){
			
		
			//Initialize Title Container
			$titles = array();
			
			//Get the response
			$content = $response->getBody();
		
			//Parse XML and save titles into contains.
			$simpleXml = simplexml_load_string($content);
			
			//Instantiate Title Objects.
			require_once "Netflix/Title.php";
			foreach($simpleXml->similars_item as $title){
			
				$Title = new Zend_Service_Netflix_Title();
				$Title->loadXML($title);
				
				array_push($titles, $Title);
				
			}
		
			return $titles;	
			
		}else{
			throw new Zend_Service_Exception($response->getMessage());
		}

    	
    }  
      
      
    /**
     * Returns a list of actors, directors, etc matching
     * the submited name as Zend_Service_Netflix_Person Objects.
     * 
     * Options:
     * start_index, max_results 
     * 
     * API CALL:
     * /catalog/people
     * 
     * @param String $name 
     * @param array $options
     */  
    public function getPeople($name, array $options=array()){
    	
    	//Validate name
		if(empty($name)){
			throw new Zend_Service_Exception("Missing Name parameter.");
		}
		
		//Method
		$method = "/catalog/people";
		
		//Options
		$options['term']   = $name;
		$options['expand'] = "filmography";
		$options 		   = $this->_buildOptions($options);
		
		//Call REST API
		$restClient = $this->_getRestClient();
		$response   = $restClient->restGet($method, $options);
		
		if(!$response->isError()){
			
			//Initialize people container
			$people = array();
			
			//Get the content 
			$content = $response->getBody();
			
			//Create SimpleXML Object 
			$xml = simplexml_load_string($content);

			require_once "Netflix/Person.php";
			//Create a Person Object for each person found.
			foreach($xml->person as $person){
			
				$NetflixPerson = new Zend_Service_Netflix_Person();
				$NetflixPerson->loadXML($person);
				array_push($people, $NetflixPerson);
			}
			
			return $people;
			
		}else{
			
			throw new Zend_Service_Exception($response->getMessage());
			
		}
    	
    }  
      
  
    /**
     * Return a specific person as a Person Object.
     *
     * @param String $personId Id of Person.
     * @return Object Zend_Service_Netflix_Person
     */  
    public function getPerson($personId){
    	
    	//Validate name
		if(empty($personId)){
			throw new Zend_Service_Exception("Missing Person Id.");
		}
		
		//Method
		$method = "/catalog/people/".$personId;
		
		//Options
		$options['expand'] = "filmography";
		$options           = $this->_buildOptions($options);
		
		//Call REST API
		$restClient = $this->_getRestClient();
		$response   = $restClient->restGet($method, $options);
		
		if(!$response->isError()){
			
			//Get the content 
			$content = $response->getBody();
			
			//Create SimpleXML Object 
			$xml = simplexml_load_string($content);

			require_once "Netflix/Person.php";
			$Person = new Zend_Service_Netflix_Person();
			$Person->loadXML($xml);
			
			return $Person;
			
		}else{
			throw new Zend_Service_Exception($response->getMessage());
		}
    	
    	
    }  
      
  

    /**
     * Creates an instance of a rest client to use
     *
     * @return Zend_Rest_Client
     */  
    protected function _getRestClient(){
    	
    	if($this->_restClient === null){
		
			require_once "Zend/Rest/Client.php";
			$this->_restClient = new Zend_Rest_Client(self::URI_BASE);
				
		}
		
		return $this->_restClient;
		
    }  
      
      
    /**
     * Creates a randomly generated value used in the 
     * oauth_nonce parameter.
     *
     * @return String
     */  
    protected function _getOAuthNOnce(){
    	
    	return time();
    	
    }  
      
         
    /**
     * Creates time stamp.  Used as
     * oauth_timestamp parameter value.
     *
     * @return String
     */  
    protected function _getOAuthTimeStamp(){
    	
    	return time();
    	
    }  
      
      
    /**
     * Generate the Oauth Default Options that is required for all 
     * Netflix API calls.
     *
     * @return Array
     */  
    protected function _getOauthDefaultOptions($enableAccessToken=false){
    	
    	$defaultOptions = array("oauth_consumer_key"     	=> $this->_consumerKey,
							    "oauth_nonce"			  	=> self::_getOAuthNOnce(),
							    "oauth_signature"			=> urlencode($this->_sharedSecret."&"),
							    "oauth_signature_method" 	=> self::SIGNITURE_METHOD,
					   		    "oauth_timestamp"        	=> self::_getOAuthTimeStamp(),
					   		    "oauth_version" 			=> self::VERSION);

		//If AccessToken Options are enabled add more options
		if($enableAccessToken){
			$defaultOptions['oauth_token']	    = $this->_accessToken;
			$defaultOptions['oauth_signature']	= urlencode($this->_sharedSecret."&".$accessTokenSecret);   		    
		}
					   		     
		return $defaultOptions;			
    	
				
    }  
      
      
      
    /**
     * Buld options to send to the API call. Merges user entered
     * query options with the default required options returned by
     * _getOauthDefaultOptions
     *
     * @param array $options
     * @return Boolean $enableAccessToken Set to true is were access user restricted data.
     */  
    protected function _buildOptions(array $options=array(), $enableAccessToken=false){
    	
		return array_merge($options, $this->_getOauthDefaultOptions($enableAccessToken));
	
    }  
      
      
    /**
     * Get the request token information from Netflix.
     */  
    protected function _getRequestTokenData(){}  
      
      
          
    /**
     * Creates URL for the application to direct the user
     * to grant access to the Application.
     * 
     * Response generates user_id, access_token, and acess_token_secret
     * This data is unique to each user and must be stored locally if 
     * application needs to use it at a future date.
     * 
     * 
     * @param String $callbackURL URL to snd the user to after granting access to your app.
     * @return String Formated URL
     */  
    public function getRequestTokenAuthorizationURL($callbackURL){}  
      
      
    /**
     * Generate Access Token Data.
     *
     * @param String $requestedToken
     * @param String $requestedTokenSecret
     */  
    public function getAccessTokenData($requestedToken, $requestedTokenSecret){}  
      
      
    /**
     * Return the Access Token.
     *
     * @return String $this->_accessToken.
     */  
    public function getAccessToken(){}  
      
    /**
     * Return the Access Token Secret
     *
     * @return String
     */  
    public function getAccessTokenSecret(){}  
      
    /**
     * Return the user id.
     *
     * @return String
     */  
    public function getUserId(){}  
      
    /**
     * Set the Access Token that is returned by the redict done 
     * at Netflix after the user grants the App access.
     *
     * @param String $accessToken
     */  
    public function setAccessToken($accessToken){}  
      
      
    /**
     * Set the Access Token that is returned by the redict done 
     * at Netflix after the user grants the App access.
     *
     * @param String $accessToken
     */  
    public function setAccessTokenSecret($accessTokenSecret){}  
  
} 